import { ApiMsgEnum, EntityTypeEnum, IClientInput, IMsgClientSync, InputTypeEnum, IState, toFixed } from '../Common'
import { Connection } from '../Core'
import { Player } from './Player'
import { PlayerManager } from './PlayerManager'
import { RoomManager } from './RoomManager'

export class Room {
  id: number
  players: Set<Player> = new Set()
  lastTime: number
  lastPlayerFrameIdMap: Map<number, number> = new Map()

  pendingInput: IClientInput[] = []

  constructor(rid: number) {
    this.id = rid
  }

  join(uid: number) {
    const player = PlayerManager.Instance.idMapPlayer.get(uid)
    if (player) {
      player.rid = this.id
      this.players.add(player)
    }
  }

  leave(uid: number) {
    const player = PlayerManager.Instance.idMapPlayer.get(uid)
    if (player) {
      player.rid = null
      this.players.delete(player)
      if (this.players.size === 0) {
        RoomManager.Instance.closeRoom(this.id)
      }
    }
  }

  close() {
    this.players.clear()
  }

  start() {
    const state: IState = {
      actors: [...this.players].map((player, index) => {
        return {
          id: player.id,
          nickname: player.nickname,
          hp: 100,
          type: index === 0 ? EntityTypeEnum.Actor1 : EntityTypeEnum.Actor2,
          weaponType: index === 0 ? EntityTypeEnum.Weapon1 : EntityTypeEnum.Weapon2,
          bulletType: index === 0 ? EntityTypeEnum.Bullet1 : EntityTypeEnum.Bullet2,
          position: {
            x: -150 + index * 300,
            y: -150 + index * 300
          },
          direction: {
            x: index === 0 ? 1 : -1,
            y: 0
          }
        }
      }),
      bullets: [],
      nextBulletId: 1,
      seed: 1
    }

    for (const player of this.players) {
      player.connection.sendMsg(ApiMsgEnum.MsgGameStart, {
        state
      })

      // 监听玩家输入
      player.connection.listenMsg(ApiMsgEnum.MsgClientSync, this.getClientMsg, this)
    }

    // 每100ms发送一次玩家输入
    setInterval(() => {
      this.sendServerMsg()
    }, 100)

    // 每16ms更新一次时间流逝
    setInterval(() => {
      this.timePast()
    }, 16)
  }

  // 收集玩家输入
  getClientMsg(connection: Connection, { input, frameId }: IMsgClientSync) {
    this.pendingInput.push(input)
    // 记录玩家最新帧id
    this.lastPlayerFrameIdMap.set(connection.playerId, frameId)
  }

  // 发送玩家输入
  sendServerMsg() {
    const inputs = this.pendingInput
    this.pendingInput = []

    for (const player of this.players) {
      player.connection.sendMsg(ApiMsgEnum.MsgServerSync, {
        lastFrameId: this.lastPlayerFrameIdMap.get(player.id) ?? 0,
        inputs
      })
    }
  }

  sync() {
    for (const player of this.players) {
      player.connection.sendMsg(ApiMsgEnum.MsgRoom, {
        room: RoomManager.Instance.getRoomView(this)
      })
    }
  }

  timePast() {
    const now = process.uptime()
    const dt = now - (this.lastTime ?? now)
    this.pendingInput.push({ type: InputTypeEnum.TimePast, dt: toFixed(dt) })
    this.lastTime = now
  }
}
